#region Copyright (c) 2006-2010 Widgetsphere LLC, All Rights Reserved
//--------------------------------------------------------------------- *
//                          Widgetsphere  LLC                           *
//             Copyright (c) 2006-2010 All Rights reserved              *
//                                                                      *
//                                                                      *
//This file and its contents are protected by United States and         *
//International copyright laws.  Unauthorized reproduction and/or       *
//distribution of all or any portion of the code contained herein       *
//is strictly prohibited and will result in severe civil and criminal   *
//penalties.  Any violations of this copyright will be prosecuted       *
//to the fullest extent possible under law.                             *
//                                                                      *
//THE SOURCE CODE CONTAINED HEREIN AND IN RELATED FILES IS PROVIDED     *
//TO THE REGISTERED DEVELOPER FOR THE PURPOSES OF EDUCATION AND         *
//TROUBLESHOOTING. UNDER NO CIRCUMSTANCES MAY ANY PORTION OF THE SOURCE *
//CODE BE DISTRIBUTED, DISCLOSED OR OTHERWISE MADE AVAILABLE TO ANY     *
//THIRD PARTY WITHOUT THE EXPRESS WRITTEN CONSENT OF WIDGETSPHERE LLC   *
//                                                                      *
//UNDER NO CIRCUMSTANCES MAY THE SOURCE CODE BE USED IN WHOLE OR IN     *
//PART, AS THE BASIS FOR CREATING A PRODUCT THAT PROVIDES THE SAME, OR  *
//SUBSTANTIALLY THE SAME, FUNCTIONALITY AS ANY WIDGETSPHERE PRODUCT.    *
//                                                                      *
//THE REGISTERED DEVELOPER ACKNOWLEDGES THAT THIS SOURCE CODE           *
//CONTAINS VALUABLE AND PROPRIETARY TRADE SECRETS OF WIDGETSPHERE,      *
//INC.  THE REGISTERED DEVELOPER AGREES TO EXPEND EVERY EFFORT TO       *
//INSURE ITS CONFIDENTIALITY.                                           *
//                                                                      *
//THE END USER LICENSE AGREEMENT (EULA) ACCOMPANYING THE PRODUCT        *
//PERMITS THE REGISTERED DEVELOPER TO REDISTRIBUTE THE PRODUCT IN       *
//EXECUTABLE FORM ONLY IN SUPPORT OF APPLICATIONS WRITTEN USING         *
//THE PRODUCT.  IT DOES NOT PROVIDE ANY RIGHTS REGARDING THE            *
//SOURCE CODE CONTAINED HEREIN.                                         *
//                                                                      *
//THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE.              *
//--------------------------------------------------------------------- *
#endregion
using System;
using System.Collections;
using System.Xml;
using System.ComponentModel;
using Widgetsphere.Generator.Common.Util;
using Widgetsphere.Generator.Common.GeneratorFramework;

namespace Widgetsphere.Generator.Models
{
  public class Parameter : BaseModelObject
  {
    #region Member Variables

    protected const System.Data.SqlDbType _def_type = System.Data.SqlDbType.VarChar;
    protected const int _def_length = 1;
    protected const bool _def_allowNull = true;
    protected const bool _def_generated = true;
    protected const bool _def_isOutputParameter = false;

    protected int _id = 0;
    protected string _name = "";
    protected string _description = "";
    protected System.Data.SqlDbType _type = _def_type;
    protected int _length = _def_length;
    protected bool _generated = _def_generated;
    protected bool _allowNull = _def_allowNull;
    protected string _default = "";
    protected Reference _parentTableRef = null;
    protected Reference _relationshipRef = null;
    protected int _sortOrder = 0;
    private string _enumType = "";
    private bool _isOutputParameter = _def_isOutputParameter;

    #endregion

    #region Constructor

    public Parameter(IModelObject root)
      : base(root)
    {
    }

    #endregion

    #region Property Implementations

    [
    Browsable(true),
    Description("Should this parameter be generated as part of the default table."),
    Category("Data"),
    DefaultValue(_def_generated),
    ]
    public bool Generated
    {
      get { return _generated; }
      set
      {
        _generated = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("generated"));
      }
    }

    [
    Browsable(true),
    Description("Determines the name of this parameter."),
    Category("Design"),
    DefaultValue(""),
    ]
    public string Name
    {
      get { return _name; }
      set
      {
        _name = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Name"));
      }
    }

    [
    Browsable(true),
    Description("Determines description text were applicable."),
    Category("Data"),
    DefaultValue(""),
    ]
    public string Description
    {
      get { return _description; }
      set
      {
        _description = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Description"));
      }
    }

    [Browsable(false)]
    public Reference RelationshipRef
    {
      get { return _relationshipRef; }
      set { _relationshipRef = value; }
    }

    [
    Browsable(true),
    Description("Determines the default value of this parameter."),
    Category("Data"),
    DefaultValue(""),
    ]
    public string Default
    {
      get { return _default; }
      set
      {
        _default = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Default"));
      }
    }

    [
    Browsable(true),
    Description("Determines the size in bytes of this parameter."),
    Category("Data"),
    DefaultValue(_def_length),
    ]
    public int Length
    {
      get
      {
        int retval = this.GetPredefinedSize();
        if(retval == -1)
          retval = _length;
        return retval;
      }
      set
      {
        if(value <= 0)
          value = 1;
        _length = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("Length"));
      }
    }

    [Browsable(false)]
    public int Id
    {
      get { return _id; }
    }

    [Browsable(false)]
    public int SortOrder
    {
      get { return _sortOrder; }
      set
      {
        _sortOrder = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("sortOrder"));
      }
    }

    [Browsable(false)]
    public Reference ParentTableRef
    {
      get { return _parentTableRef; }
      set { _parentTableRef = value; }
    }

    [
    Browsable(true),
    Description("Determines the data type of this parameter."),
    Category("Data"),
    DefaultValue(System.Data.SqlDbType.VarChar),
    ]
		public System.Data.SqlDbType DataType
		{
			get { return _type; }
			set
			{
				if (!Column.IsSupportedType(value, ((ModelRoot)this.Root).SQLServerType))
				{
					throw new Exception("Unsupported type");
				}
				_type = value;
				this.OnPropertyChanged(this, new PropertyChangedEventArgs("Type"));
			}
		}

    [
    Browsable(true),
    Description("Determines if this parameter allows null values."),
    Category("Data"),
    DefaultValue(_def_allowNull),
    ]
    public bool AllowNull
    {
      get { return _allowNull; }
      set
      {
        _allowNull = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("allowNull"));
      }
    }

    internal string EnumType
    {
      get { return _enumType; }
      set { _enumType = value; }
    }

    [
    Browsable(true),
    Description("Determines if this parameter is an output parameter."),
    Category("Data"),
    DefaultValue(_def_isOutputParameter),
    ]
    public bool IsOutputParameter
    {
      get { return _isOutputParameter; }
      set
      {
        _isOutputParameter = value;
        this.OnPropertyChanged(this, new PropertyChangedEventArgs("isOutputParameter"));
      }
    }

    #endregion

    #region Methods

    public override string ToString()
    {
      string sizeString = "";
      if(this.GetPredefinedSize() == -1)
        sizeString = "(" + this.Length + ")";

      string retval = this.Name;
      return retval;

      retval += " (" + (this.IsOutputParameter ? "out " : "") + this.DataType.ToString().ToLower() + sizeString + ", " + (this.AllowNull ? "Null" : "Not Null") + ")";
      return retval;
    }

    #endregion

    #region IXMLable Members

    public override void XmlAppend(XmlNode node)
    {
      try
      {
        XmlDocument oDoc = node.OwnerDocument;

        XmlAttribute keyNode = oDoc.CreateAttribute("key");
        keyNode.Value = this.Key.ToString();
        node.Attributes.Append(keyNode);

        XmlHelper.AddAttribute((XmlElement)node, "generated", Generated.ToString());

        XmlAttribute name = oDoc.CreateAttribute("name");
        name.Value = this.Name;
        node.Attributes.Append(name);

        XmlAttribute description = oDoc.CreateAttribute("description");
        description.Value = this.Description;
        node.Attributes.Append(description);

        if(RelationshipRef != null)
        {
          XmlNode relationshipRefNode = oDoc.CreateElement("relationshipRef");
          RelationshipRef.XmlAppend(relationshipRefNode);
          node.AppendChild(relationshipRefNode);
        }

        XmlAttribute defaultVal = oDoc.CreateAttribute("default");
        defaultVal.Value = this.Default;
        node.Attributes.Append(defaultVal);

        XmlAttribute length = oDoc.CreateAttribute("length");
        length.Value = this.Length.ToString();
        node.Attributes.Append(length);

        XmlAttribute id = oDoc.CreateAttribute("id");
        id.Value = this.Id.ToString();
        node.Attributes.Append(id);

        XmlAttribute sortOrder = oDoc.CreateAttribute("sortOrder");
        sortOrder.Value = this.SortOrder.ToString();
        node.Attributes.Append(sortOrder);

        XmlNode parentTableRefNode = oDoc.CreateElement("parentTableRef");
        this.ParentTableRef.XmlAppend(parentTableRefNode);
        node.AppendChild(parentTableRefNode);

        XmlAttribute type = oDoc.CreateAttribute("type");
        type.Value = this.DataType.ToString("d");
        node.Attributes.Append(type);

        XmlAttribute allowNull = oDoc.CreateAttribute("allowNull");
        allowNull.Value = this.AllowNull.ToString();
        node.Attributes.Append(allowNull);

        XmlAttribute isOutputParameter = oDoc.CreateAttribute("isOutputParameter");
        isOutputParameter.Value = this.IsOutputParameter.ToString();
        node.Attributes.Append(isOutputParameter);

      }
      catch(Exception ex)
      {
        throw;
      }
    }

    public override void XmlLoad(XmlNode node)
    {
      try
      {
        _key = XmlHelper.GetAttributeValue(node, "key", _key);
        this.Generated = XmlHelper.GetAttributeValue(node, "generated", _def_generated);
        this.Name = node.Attributes["name"].Value;
        this.Description = node.Attributes["description"].Value;
        XmlNode relationshipRefNode = node.SelectSingleNode("relationshipRef");
        if(relationshipRefNode != null)
        {
          RelationshipRef = new Reference(this.Root);
          RelationshipRef.XmlLoad(relationshipRefNode);
        }

        this.Default = node.Attributes["default"].Value;
				this.Length = XmlHelper.GetAttributeValue(node, "length", _length);
        this.SetId(XmlHelper.GetAttributeValue(node, "id", _id));
        this.SortOrder = XmlHelper.GetAttributeValue(node, "sortOrder", _sortOrder);

        XmlNode parentTableRefNode = node.SelectSingleNode("parentTableRef");
        ParentTableRef = new Reference(this.Root);
        ParentTableRef.XmlLoad(parentTableRefNode);

        string typeString = node.Attributes["type"].Value;
        if(typeString != "")
          this.DataType = (System.Data.SqlDbType)int.Parse(typeString);

        this.AllowNull = XmlHelper.GetAttributeValue(node, "allowNull", _allowNull);
        this.IsOutputParameter = XmlHelper.GetAttributeValue(node, "isOutputParameter", _isOutputParameter);

        this.Dirty = false;
      }
      catch(Exception ex)
      {
        throw;
      }

    }

    #endregion

    #region Helpers

    public Reference CreateRef()
    {
      Reference returnVal = new Reference(this.Root);
      returnVal.Ref = this.Id;
      returnVal.RefType = ReferenceType.Parameter;
      return returnVal;
    }

    [Browsable(false)]
    public string CamelName
    {
			//get { return StringHelper.DatabaseNameToCamelCase(this.Name); }
			get { return StringHelper.DatabaseNameToCamelCase(this.PascalName); }
		}

    [Browsable(false)]
    public string PascalName
    {
			get
			{
				if (((ModelRoot)this.Root).TransformNames)
					return StringHelper.DatabaseNameToPascalCase(this.Name);
				else if (!(((ModelRoot)this.Root).TransformNames))
					return this.Name;
				return this.Name; //Default
			}
    }

    [Browsable(false)]
    public string DatabaseName
    {
      get { return this.Name; }
    }

		public string GetCodeType()
		{
			return GetCodeType(true);
		}

		public string GetCodeType(bool allowNullable)
		{
			string retval = "";
			if (this.EnumType != "")
			{
				retval = this.EnumType;
			}
			else if (StringHelper.Match(this.DataType.ToString(), "bigint", true))
			{
				retval = "long";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "binary", true))
			{
				return "System.Byte[]";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "bit", true))
			{
				retval = "bool";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "char", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "datetime", true))
			{
				retval = "DateTime";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "decimal", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "float", true))
			{
				retval = "double";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "image", true))
			{
				return "System.Byte[]";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "int", true))
			{
				retval = "int";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "money", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "nchar", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "ntext", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "numeric", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "nvarchar", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "real", true))
			{
				retval = "System.Single";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "smalldatetime", true))
			{
				retval = "DateTime";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "smallint", true))
			{
				retval = "short";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "smallmoney", true))
			{
				retval = "decimal";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "variant", true))
			{
				retval = "object";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "text", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "tinyint", true))
			{
				retval = "byte";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "uniqueidentifier", true))
			{
				retval = "System.Guid";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "varbinary", true))
			{
				return "System.Byte[]";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "varchar", true))
			{
				return "string";
			}
			else if (StringHelper.Match(this.DataType.ToString(), "timestamp", true))
			{
				return "System.Byte[]";
			}
			else
			{
				throw new Exception("Cannot Map Sql Value To C# Value");
			}

			if (allowNullable && this.AllowNull)
				retval += "?";

			return retval;

		}

    /// <summary>
    /// Determines if the Datatype suppors the 'Parse' method
    /// </summary>
    [Browsable(false)]
    public bool AllowStringParse
    {
      get
      {
        if(StringHelper.Match(this.DataType.ToString(), "bigint", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "binary", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "bit", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "char", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "datetime", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "decimal", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "float", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "image", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "int", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "money", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "nchar", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "ntext", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "numeric", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "nvarchar", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "real", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "smalldatetime", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "smallint", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "smallmoney", true))
        {
          return true;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "variant", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "text", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "tinyint", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "uniqueidentifier", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "varbinary", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "varchar", true))
        {
          return false;
        }
        else if(StringHelper.Match(this.DataType.ToString(), "timestamp", true))
        {
          return false;
        }
        else
        {
          return false;
        }
      }
    }

		protected internal void SetKey(string key)
		{
			_key = key;
		}

    protected internal void SetId(int id)
    {
      _id = id;
    }

    public int GetPredefinedSize()
    {
      //Returns -1 if variable
      switch(this.DataType)
      {
        case System.Data.SqlDbType.BigInt:
          return 8;
        case System.Data.SqlDbType.Bit:
          return 1;
        case System.Data.SqlDbType.DateTime:
          return 8;
        case System.Data.SqlDbType.Decimal:
          return 13;
        case System.Data.SqlDbType.Float:
          return 8;
        case System.Data.SqlDbType.Int:
          return 4;
        case System.Data.SqlDbType.Money:
          return 8;
        case System.Data.SqlDbType.Real:
          return 4;
        case System.Data.SqlDbType.SmallDateTime:
          return 4;
        case System.Data.SqlDbType.SmallInt:
          return 2;
        case System.Data.SqlDbType.SmallMoney:
          return 4;
        case System.Data.SqlDbType.Timestamp:
          return 8;
        case System.Data.SqlDbType.TinyInt:
          return 1;
        case System.Data.SqlDbType.UniqueIdentifier:
          return 16;
				case System.Data.SqlDbType.NText:
					return 0;
				default:
          return -1;
      }
    }

    #endregion

  }
}